/*
 * @Date         : 2023-08-06 12:51:42
 * @Description  : 请求实例
 */

import store from "@/store"
import Request from "@/request/request"
import * as config from "@/config"
import { isEmpty } from "@/utils/check"
import { formatDate } from "@/utils/date"
import { uuid, merge, delay } from "@/utils/utils"
import { encodeVerifyInfo } from "@/utils/encode"

// 最美业务请求实例
const request = new Request({
  queue: "await",
  checkToken: true,
  baseUrl: store.getters.api,
  requestIntercept: handleRequestIntercept,
  responseIntercept: handleResponseIntercept,
  errorIntercept: handleErrorIntercept
})

// 请求拦截
const queues = []
async function handleRequestIntercept(req) {
  return new Promise((resolve) => {
    handlePrintRequest(req)
    req.id = uuid()
    req.originData = req.data
    req.data = handleGenRequestData(req.data)
    req.task = (task, options) => {
      if (options.login && isEmpty(store.state.user.login)) task.abort()
    }
    const queue = {
      id: req.id,
      url: req.url,
      queue: req.queue,
      next: () => {
        req.data = handleGenRequestData({ ...req.originData, tokenId: uni.getStorageSync("token") })
        const index = queues.findIndex((item) => item.id === req.id)
        const isExistSync = queues.some((item) => item.queue === "sync")
        const isExistAsync = queues.some((item) => item.queue === "async")

        switch (req.queue) {
          case "sync":
            if (index === 0) resolve(req)
            break
          case "async":
            if (!isExistSync) resolve(req)
            break
          default:
            if (!isExistSync && !isExistAsync) setTimeout(() => resolve(req), 0)
            break
        }
      }
    }
    if (queues.length) {
      const syncIndex = queues.findLastIndex((item) => item.queue === "sync")
      const asyncIndex = queues.findLastIndex((item) => item.queue === "async")
      switch (req.queue) {
        case "sync":
          queues.splice(syncIndex + 1, 0, queue)
          break
        case "async":
          queues.splice((asyncIndex < 0 ? syncIndex : asyncIndex) + 1, 0, queue)
          break
        default:
          queues.push(queue)
          break
      }
    } else {
      queues.push(queue)
      queue.next()
    }
    req.completeCallback = (options) => {
      setTimeout(() => {
        const index = queues.findIndex((item) => item.id === options.id)
        queues.splice(index, 1)
        queues.forEach((queue) => queue.next())
      }, 0)
    }
  })
}

// 响应拦截
async function handleResponseIntercept(res, options) {
  // 业务请求成功
  if (res.status === "00000") return res

  // 登录信息失效
  const clearStatus = ["10005"]
  if (clearStatus.includes(res.status)) store.dispatch("clearUserInfo")

  // token失效为10001  有效token请求不属于的渠道为10003
  const reloadStatus = ["10001", "10003"]
  if (reloadStatus.includes(res.status)) {
    const isExistTokenReq = queues.some((item) => item.url.includes("/getToken"))
    if (isExistTokenReq) {
      if (options.loop == false) {
        const data = await request[options.method.toLowerCase()](options.api, options.originData, { handleError: options.handleError, queue: options.queue, loop: true })
        return { data }
      }
    } else {
      delete options.data.tokenId
      delete options.originData.tokenId
      if (res.status == "10003") await store.dispatch("clearToken")
      await store.dispatch("getToken")
      await delay(30)
      const data = await request[options.method.toLowerCase()](options.api, options.originData, { handleError: options.handleError, queue: options.queue, loop: true })
      return { data }
    }
  } else if (res.status === "200000") {
    uni.$dialog({
      title: "提示",
      content: res.content,
      onConfirm: () => {
        uni.switchTab({ url: "/pages/tabbar/tabbar-1/tabbar-1" })
      }
    })
  } else if (options.handleError) {
    const loginStatus = ["10005", "10006"]
    const routes = getCurrentPages()
    const route = routes[routes.length - 1]?.route
    if (loginStatus.includes(res?.status)) {
      await delay(1000)
      uni.$emit(`${route}-login`)
    } else {
      await delay(30)
      uni.$emit(`${route}-error`, { title: "提示", content: res.content ? res.content : `api:${options.api},status:${res.status}` })
    }
  }
}

// 错误拦截
async function handleErrorIntercept(error, options) {
  return new Promise((resolve) => {
    error.api = options.api
    if (error.errMsg === "request:fail abort") {
      error.message = "已终止请求"
      if (options.login) error.message = `[${options.api}] 接口需要登录，已终止请求`
    } else if (error.errMsg === "request:fail timeout") {
      error.message = "请求超时，请检查网络或重试"
      if (options.prevUrl?.indexOf(options.api) == -1) {
        store.dispatch("errorLog", { device: JSON.stringify(uni.$systemInfo), content: `[网络超时] ${options.api}`, route: uni.$currentRoute })
      }
    } else {
      error.message = error.statusCode ? `status:${error.statusCode} \n error:${error.data.message}` : error.errMsg
      if (options.prevUrl?.indexOf(options.api) == -1) {
        store.dispatch("errorLog", { device: JSON.stringify(uni.$systemInfo), content: `[接口错误] ${JSON.stringify(error)}`, route: uni.$currentRoute })
      }
    }
    const errorSentence = ["request:fail abort", "request:fail"]
    if (options.handleError) {
      if (error.errMsg === "request:fail timeout") {
        uni.$dialog({ title: "网络请求超时", content: error.message })
      } else if (!errorSentence.includes(error.errMsg)) {
        const regex = /abort(ed)?/
        if (regex.test(error.errMsg)) return
        // uni.$dialog({ title: "请求失败", content: error.message })
      }
    }
    resolve(error)
  })
}

// 请求日志打印
function handlePrintRequest() {
  if (process.env.NODE_ENV === "development") {
    // // #ifndef APP-PLUS
    // console.log(`[${request.method}]请求地址: ${request.url}`)
    // if (uni.$check.isNoEmpty(request.data)) {
    //   console.log(`[${request.method}]请求参数: ${JSON.stringify(request.data)}`)
    // }
    // // #endif
    // // #ifdef APP-PLUS
    // console.log(`[${request.method}]请求地址: ${request.url}`)
    // if (uni.$check.isNoEmpty(request.data)) {
    //   console.log(`[${request.method}]请求参数: ${JSON.stringify(request.data)}`)
    // }
    // // #endif
  }
}

// 生成接口请求数据
export function handleGenRequestData(params = {}) {
  params = Object.entries(params).reduce((acc, [key, value]) => {
    if (value !== null && value !== undefined) acc[key] = value
    else if (value === 0) acc[key] = value
    return acc
  }, {})
  const { account, cityCode, password } = store.getters
  const data = {
    requestTime: formatDate(new Date(), "YYYY-MM-DD HH:mm:ss"),
    cityId: cityCode || config.cityCode,
    account: account,
    tokenId: uni.getStorageSync("token")
  }
  const reqData = merge(data, params)
  reqData.verifyInfo = encodeVerifyInfo(reqData, password)
  return reqData
}

// 挂载接口
const apis = {}
const files = require.context("../api", false, /^(?!.*\/index\.js$).*\.js$/)
files.keys().forEach((key) => (apis[key.replace(/(\.\/|\.js)/g, "")] = files(key).default))

export const api = apis
export default function (Vue) {
  uni.$api = api
  uni.$request = request
  Vue.prototype.$api = api
  Vue.prototype.$request = request
}
